﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;

//{"copyblob": {
//	"SourceStorageAccountAlias":"AccountAliasA",
//	"TargetStorageAccountAlias":"AccountAliasB",
//	"source":
//		{"blobname":"golive_blob", 
//       "containername":"mycontainer"},
//	"target":
//		{"blobname":"golive_blob_copy", 
//       "containername":"mycontainer"}
//	}
//}

namespace wamr.Worker
{
    class CopyBlobTask: ManagerTask
    {
        // input parameters
        private string _sourceStorageAccountAlias = "";
        private string _targetStorageAccountAlias = "";
        private string _sourceBlobName = "";
        private string _sourceContainerName = "";
        private string _targetBlobName = "";
        private string _targetContainerName = "";
        
        // retrieved from config settings


        // other instance variables
        private bool storageInitialized = false;
        private CloudBlobClient cbcA = null;
        private CloudBlobClient cbcB = null;
        private string _copyBlobOperationID = string.Empty;

        public CopyBlobTask(string ManagerMessage)
        {
            MessageIsValid = true;
            TaskType = "CopyBlob";

            JSONClasses.JSONCopyBlobRootObject r = JsonConvert.DeserializeObject<JSONClasses.JSONCopyBlobRootObject>(ManagerMessage);

            if (string.IsNullOrEmpty(r.copyblob.sourcestorageaccountalias) ||
                string.IsNullOrEmpty(r.copyblob.targetstorageaccountalias) ||
                string.IsNullOrEmpty(r.copyblob.source.blobname) ||
                string.IsNullOrEmpty(r.copyblob.source.containername) ||
                string.IsNullOrEmpty(r.copyblob.target.blobname) ||
                string.IsNullOrEmpty(r.copyblob.target.containername))
            {
                MessageIsValid = false;
                Trace.TraceError("All parameters are required.");
                return;
            }

            _sourceStorageAccountAlias = r.copyblob.sourcestorageaccountalias;
            _targetStorageAccountAlias = r.copyblob.targetstorageaccountalias;

            _sourceBlobName = r.copyblob.source.blobname;
            _sourceContainerName = r.copyblob.source.containername;

            _targetBlobName = r.copyblob.target.blobname;
            _targetContainerName = r.copyblob.target.containername;

        }

        public override bool PreConditionsMet()
        {
            TaskDisposition = TaskDispositionEnum.PROCEED;
            return true;
        }

        public override bool Initiate()
        {
            Trace.TraceInformation("Entered the CopyBlob Initiate routine.");

            if (!InitializeStorageHelper())
            {
                TaskDisposition = TaskDispositionEnum.FAIL;
                return false;
            }

            CloudBlobContainer sourceContainer = null;
            CloudBlobContainer targetContainer = null;

            try
            {
                sourceContainer = cbcA.GetContainerReference(_sourceContainerName);
                targetContainer = cbcB.GetContainerReference(_targetContainerName);
            }
            catch (Exception ex)
            {
                Trace.TraceError(string.Format("CopyBlob/Initiate: Error creating storage container references: {0}", ex.Message));
                TaskDisposition = TaskDispositionEnum.FAIL;
                return false;
            }

            CloudBlockBlob sourceBlob = null;
            CloudBlockBlob targetBlob = null;

            try
            {
                sourceBlob = sourceContainer.GetBlockBlobReference(_sourceBlobName);
                targetBlob = targetContainer.GetBlockBlobReference(_targetBlobName);
            }
            catch (Exception ex)
            {
                Trace.TraceError(string.Format("CopyBlob/Initiate: Error creating blob references: {0}", ex.Message));
                TaskDisposition = TaskDispositionEnum.FAIL;
                return false;
            }

            if (sourceBlob.Properties.BlobType == BlobType.PageBlob)
            {
                Trace.TraceError("CopyBlob/Initiate: Input blob is a page blob - currently unsupported.");
                TaskDisposition = TaskDispositionEnum.FAIL;
                _copyBlobOperationID = string.Empty;
                return false;
            }

            try
            {
                _copyBlobOperationID = targetBlob.StartCopyFromBlob(sourceBlob);
            }
            catch (Exception ex)
            {
                Trace.TraceError(string.Format("CopyBlob/Initiate: Error initiating blob copy operation: {0}", ex.Message));
                TaskDisposition = TaskDispositionEnum.FAIL;
                _copyBlobOperationID = string.Empty;
                return false;
            }

            Trace.TraceInformation("Exiting the CopyBlob Initiate routine.");
            return true;
        }

        public override bool Status()
        {
            Trace.TraceInformation("Entered the CopyBlob Status routine.");

            if (!InitializeStorageHelper())
                return true;

            CloudBlobContainer targetContainer = null;

            try
            {
                targetContainer = cbcB.GetContainerReference(_targetContainerName);
            }
            catch (Exception ex)
            {
                Trace.TraceError(string.Format("CopyBlob/Status: Error creating storage container reference: {0}", ex.Message));
                TaskDisposition = TaskDispositionEnum.FAIL;
                return true;
            }

            var destBlobList = targetContainer.ListBlobs(prefix:_targetBlobName, blobListingDetails: BlobListingDetails.Copy);
            if (destBlobList.Count() == 0)
            {
                Trace.TraceError("Enumerating the destination container yielded zero blobs.");
                TaskDisposition = TaskDispositionEnum.FAIL;
                return true;
            }

            var destBlob = destBlobList.FirstOrDefault() as CloudBlockBlob;
            CopyState cs = destBlob.CopyState;
            if (cs.Status == CopyStatus.Success)
            {
                Trace.TraceInformation("CopyBlob Status routine: Copy succeeded according to CopyState.");
                TaskDisposition = TaskDispositionEnum.COMPLETE;
            }
            else if (cs.Status == CopyStatus.Failed || cs.Status == CopyStatus.Aborted || cs.Status == CopyStatus.Invalid)
            {
                Trace.TraceInformation("CopyBlob Status routine: Copy failed according to CopyState.");
                TaskDisposition = TaskDispositionEnum.FAIL;
            }
            else // pending
            {
                Trace.TraceInformation("CopyBlob Status routine: Proceeding with copy.");
                TaskDisposition = TaskDispositionEnum.PROCEED;
            }

            Trace.TraceInformation("Exiting the CopyBlob Status routine.");
            return true;
        }

        public override void ResolveDependency()
        {
            // no dependencies so just...
            return;
        }


        private bool InitializeStorageHelper()
        {
            if (storageInitialized)
            {
                return true;
            }

            try
            {
                // read wamr storage account configuration settings
                string storageAccountAconnection = CloudConfigurationManager.GetSetting(_sourceStorageAccountAlias);
                if (storageAccountAconnection == null)
                    throw new ArgumentNullException("SourceStorageAccountAlias", "Invalid value for storage account alias was provided.");

                string storageAccountBconnection = CloudConfigurationManager.GetSetting(_targetStorageAccountAlias);
                if (storageAccountBconnection == null)
                    throw new ArgumentNullException();

                // parse the connection strings & create objects

                // SOURCE
                Microsoft.WindowsAzure.Storage.CloudStorageAccount storageAccountA;
                if (Microsoft.WindowsAzure.Storage.CloudStorageAccount.TryParse(storageAccountAconnection, out storageAccountA))
                {
                    // create the blob storage client
                    cbcA = storageAccountA.CreateCloudBlobClient();

                }

                // TARGET
                Microsoft.WindowsAzure.Storage.CloudStorageAccount storageAccountB;
                if (Microsoft.WindowsAzure.Storage.CloudStorageAccount.TryParse(storageAccountBconnection, out storageAccountB))
                {
                    // create the blob storage client
                    cbcB = storageAccountB.CreateCloudBlobClient();

                    // and the destination container 
                    CloudBlobContainer container = cbcB.GetContainerReference(_targetContainerName);
                    container.CreateIfNotExists();
                }

            }
            catch (Exception ex)
            {
                Trace.TraceError(string.Format("Error initializing storage: {0}", ex.Message));
                return false;
            }

            storageInitialized = true;
            return true;
        }
    }
}
